using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GameFramework.Fsm;
using GameFramework.Event;
using GameFramework.Resource;
using UnityGameFramework.Runtime;
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
using GFUtility = GameFramework.Utility;

namespace LS.Procedure
{
    public class ProcedurePreloadDataTable : ProcedurePreloaderBase
    {
        public override bool UseNativeDialog => false;

        public override int PreloadPriority => 10;

        private Dictionary<string, bool> m_LoadedFlag = new Dictionary<string, bool>();

        protected override void OnEnter(IFsm<GameFramework.Procedure.IProcedureManager> procedureOwner)
        {
            base.OnEnter(procedureOwner);

            LSEntry.Event.Subscribe(LoadConfigSuccessEventArgs.EventId, OnLoadConfigSuccess);
            LSEntry.Event.Subscribe(LoadConfigFailureEventArgs.EventId, OnLoadConfigFailure);
            LSEntry.Event.Subscribe(LoadDataTableSuccessEventArgs.EventId, OnLoadDataTableSuccess);
            LSEntry.Event.Subscribe(LoadDataTableFailureEventArgs.EventId, OnLoadDataTableFailure);
            LSEntry.Event.Subscribe(LoadDictionarySuccessEventArgs.EventId, OnLoadDictionarySuccess);
            LSEntry.Event.Subscribe(LoadDictionaryFailureEventArgs.EventId, OnLoadDictionaryFailure);
            
            m_LoadedFlag.Clear();

            PreloadResources();
        }

        protected override void OnUpdate(IFsm<GameFramework.Procedure.IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);

            foreach (KeyValuePair<string, bool> loadedFlag in m_LoadedFlag)
            {
                if (!loadedFlag.Value)
                {
                    return;
                }
            }
            ChangeNextProcedure(GetNextProcedureType());
        }

        protected override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
        {
            LSEntry.Event.Unsubscribe(LoadConfigSuccessEventArgs.EventId, OnLoadConfigSuccess);
            LSEntry.Event.Unsubscribe(LoadConfigFailureEventArgs.EventId, OnLoadConfigFailure);
            LSEntry.Event.Unsubscribe(LoadDataTableSuccessEventArgs.EventId, OnLoadDataTableSuccess);
            LSEntry.Event.Unsubscribe(LoadDataTableFailureEventArgs.EventId, OnLoadDataTableFailure);
            LSEntry.Event.Unsubscribe(LoadDictionarySuccessEventArgs.EventId, OnLoadDictionarySuccess);
            LSEntry.Event.Unsubscribe(LoadDictionaryFailureEventArgs.EventId, OnLoadDictionaryFailure);

            base.OnLeave(procedureOwner, isShutdown);
        }

        private void PreloadResources()
        {
            // Preload configs
            //LoadConfig("DefaultConfig");

            // Preload data tables
            if(DataTableGeneratingCollection.InstanceObject != null)
            {
                var dataTables = DataTableGeneratingCollection.InstanceObject.Collection;
                for (int i = 0; i < dataTables.Count; i++)
                {
                    var item = dataTables[i];
                    LoadDataTable(item.Name, item.FilePath);
                }
            }

            //加载拓展配置
            //LoadExtendsConfigs("ExtendsConfigs");
            
            //LoadDictionary("Dictionary");
            
            //// Preload fonts
            //LoadFontConfig();
        }

        private void LoadConfig(string configName)
        {
            string configAssetName = LSPath.FormatConfigUnityAsset(configName,LSPath.TxtExtension);
            m_LoadedFlag.Add(configAssetName, false);
            LSEntry.Config.ReadData(configAssetName, this);
        }

        private void LoadDataTable(string dataTableName,string path)
        {
            m_LoadedFlag.Add(path, false);
            LSEntry.DataTable.LoadDataTable(dataTableName, path, this);
        }

        private void LoadDictionary(string dictionaryName)
        {
            string dictionaryAssetName = LSPath.FormatDictionaryUnityAsset(dictionaryName, LSPath.XMLExtension, LSEntry.Localization.Language);
            m_LoadedFlag.Add(dictionaryAssetName, false);
            LSEntry.Localization.ReadData(dictionaryAssetName, this);
        }

        private void LoadFontConfig()
        {
            string fontConfigPath = LSPath.FormatDictionaryUnityAsset("FontConfig", LSPath.TxtExtension, LSEntry.Localization.Language);
            m_LoadedFlag.Add(fontConfigPath, false);
            try
            {
                LSEntry.Config.ReadData(fontConfigPath, this);
            }
            catch (GameFramework.GameFrameworkException e)
            {
                Log.Error(e);
                m_LoadedFlag[fontConfigPath] = true;
            }
        }

        private void LoadFonts()
        {
            string legacyFontName = LSEntry.Config.GetString("LegacyFont");
            string tmpFontName = LSEntry.Config.GetString("TMPFont");
            if (!string.IsNullOrEmpty(legacyFontName))
            {
                m_LoadedFlag.Add(GFUtility.Text.Format("Font.{0}", legacyFontName), false);
                LSEntry.Resource.LoadAsset(LSPath.FormatFontUnityAsset(legacyFontName, LSPath.TTFExtension), Constant.AssetPriority.FontAsset, new LoadAssetCallbacks(
                    (assetName, asset, duration, userData) =>
                    {
                        var dataNode = LSEntry.DataNode;
                        m_LoadedFlag[GFUtility.Text.Format("Font.{0}", legacyFontName)] = true;
                        var fontData = dataNode.GetData<VarUnityObject>("LegacyFont");
                        if (fontData != null)
                        {
                            fontData.SetValue(asset);
                        }
                        else
                        {
                            LSEntry.DataNode.SetData<VarUnityObject>("LegacyFont", (Font)asset);
                        }
                        Log.Info("Load font '{0}' OK.", legacyFontName);
                    },

                    (assetName, status, errorMessage, userData) =>
                    {
                        Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", legacyFontName, assetName, errorMessage);
                    }));
            }
            if (!string.IsNullOrEmpty(tmpFontName))
            {
                m_LoadedFlag.Add(GFUtility.Text.Format("TMPFont.{0}", tmpFontName), false);
                LSEntry.Resource.LoadAsset(LSPath.FormatFontUnityAsset(tmpFontName, LSPath.UnityAssetExtension), Constant.AssetPriority.FontAsset, new LoadAssetCallbacks(
                    (assetName, asset, duration, userData) =>
                    {
                        m_LoadedFlag[GFUtility.Text.Format("TMPFont.{0}", tmpFontName)] = true;
                        var dataNode = LSEntry.DataNode;
                        var fontData = dataNode.GetData<VarUnityObject>("TMPFont");
                        if (fontData != null)
                        {
                            fontData.SetValue(asset);
                        }
                        else
                        {
                            LSEntry.DataNode.SetData<VarUnityObject>("TMPFont", (Font)asset);
                        }
                        Log.Info("Load font '{0}' OK.", tmpFontName);
                    },

                    (assetName, status, errorMessage, userData) =>
                    {
                        Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", tmpFontName, assetName, errorMessage);
                    }));
            }
        }

        private void OnLoadConfigSuccess(object sender, GameEventArgs e)
        {
            LoadConfigSuccessEventArgs ne = (LoadConfigSuccessEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            if (ne.ConfigAssetName.Contains("FontConfig"))
            {
                LoadFonts();
            }

            m_LoadedFlag[ne.ConfigAssetName] = true;
            Log.Info("Load config '{0}' OK.", ne.ConfigAssetName);

        }

        private void OnLoadConfigFailure(object sender, GameEventArgs e)
        {
            LoadConfigFailureEventArgs ne = (LoadConfigFailureEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            Log.Error("Can not load config '{0}' from '{1}' with error message '{2}'.", ne.ConfigAssetName, ne.ConfigAssetName, ne.ErrorMessage);
            m_LoadedFlag[ne.ConfigAssetName] = true;
        }

        private void OnLoadDataTableSuccess(object sender, GameEventArgs e)
        {
            LoadDataTableSuccessEventArgs ne = (LoadDataTableSuccessEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            m_LoadedFlag[ne.DataTableAssetName] = true;
            Log.Info("Load data table '{0}' OK.", ne.DataTableAssetName);
        }

        private void OnLoadDataTableFailure(object sender, GameEventArgs e)
        {
            LoadDataTableFailureEventArgs ne = (LoadDataTableFailureEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            Log.Error("Can not load data table '{0}' from '{1}' with error message '{2}'.", ne.DataTableAssetName, ne.DataTableAssetName, ne.ErrorMessage);
            m_LoadedFlag[ne.DataTableAssetName] = true;
        }

        private void OnLoadDictionarySuccess(object sender, GameEventArgs e)
        {
            LoadDictionarySuccessEventArgs ne = (LoadDictionarySuccessEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            m_LoadedFlag[ne.DictionaryAssetName] = true;
            Log.Info("Load dictionary '{0}' OK.", ne.DictionaryAssetName);
        }

        private void OnLoadDictionaryFailure(object sender, GameEventArgs e)
        {
            LoadDictionaryFailureEventArgs ne = (LoadDictionaryFailureEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            Log.Error("Can not load dictionary '{0}' from '{1}' with error message '{2}'.", ne.DictionaryAssetName, ne.DictionaryAssetName, ne.ErrorMessage);
            m_LoadedFlag[ne.DictionaryAssetName] = true;
        }
    }
}
